home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Ultimate Window Set -…Games & Quality Programs
/
The Ultimate Window Set - 250 Games & Quality Programs.iso
/
win
/
pro30
/
bitops.c
next >
Wrap
Text File
|
1987-09-22
|
13KB
|
439 lines
/* BITOPS.C - Various bit-manipulation procedures.
*
* Audit Trail
*
* 09/11/87 - v001 - GSK - Original
*/
#include "ctype.h"
#define FULLBYT 0xff
#define TBUFSIZ 100
#define SUCCESS 0
#define FAILURE -1
#define NULL (char *)0
typedef unsigned BOOL;
/* *************************** GENERAL NOTES *****************************
*
* Most of these routines deal with "bit fields" of arbitrary
* length. In general, you pass them a (char) pointer to a block of memory,
* which will be interpreted and manipulated as a stream of bits, regardless
* of byte or word boundaries after the original pointer. Several of these
* routines take a bit offset argument, which is an ABSOLUTE number of bits
* (zero-relative) from the base pointer; in other words, a bit offset of
* 75 points to the 76th bit in the block, starting from the base pointer.
*
****************************************************************************/
/* GETBIT - Get the value of the bit (0, 1) at passed ptr, offset by bitoffs
* bits. The offset may be any positive number; if >8, the byte
* pointer will be incremented accordingly.
*/
short getbit(ptr, bitoffs)
char *ptr; /* Base pointer */
short bitoffs; /* Offset from ptr in number of bits */
{
if (ptr == NULL || bitoffs < 0)
return (FAILURE);
ptr += (bitoffs / 8); /* Knock up ptr to byte requested */
bitoffs %= 8; /* Get bit relative to its own byte */
return (short)((*ptr >> (7 - bitoffs)) & 1);
}
/* SETBIT - Set a specified bit number in a char string to 1 or 0. The bit
* number may be any positive value; if > 8, the byte pointer will
* be incremented accordingly.
*/
short setbit(ptr, bitnum, val)
char *ptr; /* Base of string */
short bitnum; /* Bit number, 0 relative */
short val; /* Value to set, 1 or 0 */
{
short byteoffs; /* Byte offset in string */
char mask; /* Masking value */
if (ptr == NULL || bitnum < 0 || (val != 0 && val != 1))
return (FAILURE);
ptr += (byteoffs = bitnum / 8); /* Calc offset, reset ptr */
if (byteoffs)
bitnum %= (byteoffs * 8); /* Find bit within byte */
/* Mask = bit string of zeroes with one in bitnum position */
mask = 1 << (7 - bitnum);
if (val) /* If turn-on bit, OR with mask */
*ptr |= mask;
else /* Else, AND with inverse (ones-complement) of mask */
*ptr &= ~mask;
return (SUCCESS);
}
/* COUNTBIT - Count the bits of specified value (0 or 1) in a bit field. The
* field may be any number of bytes in length. If val==0, then
* "off" bits will be counted; otherwise, "on" bits.
*/
short countbit(basep, nbytes, val)
char *basep; /* Starting byte to begin count */
short nbytes; /* Number of bytes to count thru */
short val; /* Bit value to count, 0 or 1 */
{
short count; /* Number of bits counted */
short bit; /* Bit loop counter */
char *ptr; /* Loop pointer */
if (basep == NULL || nbytes <= 0 || (val != 0 && val != 1))
return (FAILURE);
count = 0;
for (ptr = basep; ptr < basep + nbytes; ptr++)
{
for (bit = 0; bit < 8; bit++)
count += (getbit(ptr, bit) == val);
}
return (count);
}
/* BITPATRN - Generate an array of chars or ints corresponding to the bit
* pattern of the passed char. If patyp == 'C', an array of
* character '0's and '1's will be generated; if 'I', an array
* numeric 0/1's.
*
* NOTE that you pass a single CHAR, not a char *. Thus if you
* need a pattern array more than 8 elements long, call
* bitpatrn() in a loop and concatenate the results.
*/
short bitpatrn(chr, patp, patyp)
char chr; /* Char to generate pattern from */
char *patp; /* Ptr to array of chars or ints, depending on patyp */
char patyp; /* Pattern type: Char or Int (NOT case sensitive) */
{
short ptrinc; /* Pointer increment per bit */
short bit; /* Bit counter */
short bitval; /* Bit value, 1 or 0 */
patyp = toupper(patyp);
if (patp == NULL || (patyp != 'C' && patyp != 'I'))
return (FAILURE);
ptrinc = 1 + (patyp == 'I');
for (bit = 0; bit < 8; bit++, patp += ptrinc)
{
bitval = getbit(&chr, bit);
if (patyp == 'I') /* Int array: Set low bytes of each pair */
{
*patp = bitval;
*(patp + 1) = 0;
}
else
*patp = '0' + bitval;
}
return (SUCCESS);
}
/* BYTE2BIT - Translate the byte passed to a bit pattern, placed at char
* *ptr, offset by bitoffs bits from left. Do not write onto next
* byte from ptr if lastbyt set. This allows a bit pattern to be
* copied to another place in memory regardless of byte
* boundaries. For example, if bitoffs == 3, then the left 5 bits
* of the passed byte will be copied to the right 5 bits of the
* destination ptr, and the right 3 bits of the byte onto the
* left 3 bits of the following location (unless lastbyt == YES),
* in which case only the FIRST dest char will be written on).
* Issuing a call with a ZERO bit offset, like:
*
* byte2bit('A', dest, 0, anything);
*
* is equivalent to: *dest = 'A';
*/
short byte2bit(byte, ptr, bitoffs, lastbyt)
char byte; /* Character to translate */
char *ptr; /* DESTINATION Ptr: Points to starting byte to write to */
short bitoffs; /* Offset of starting bit from DESTINATION ptr, 0-7 */
BOOL lastbyt; /* Flag: Do not write bits to next char if set */
{
short bit; /* Bit counter */
if (ptr == NULL || bitoffs < 0 || bitoffs > 7)
return (FAILURE);
/* Write left side of passed byte to right side of 1st destination char,
leaving left side of dest char unchanged */
for (bit = bitoffs; bit <= 7; bit++)
setbit(ptr, bit, getbit(&byte, bit - bitoffs));
/* Write right side of byte to left side of next destination char,
leaving right side unchanged */
if (bitoffs && !lastbyt)
for (bit = 0; bit < bitoffs; bit++)
setbit(ptr + 1, bit, getbit(&byte, bit + 8 - bitoffs));
return (SUCCESS);
}
/* BIT2BYTE.C - Take next 8 bits from starting char *, offset by specified
* number of bits (bitoffs), translate to a byte and return
* value as a char. Starting point need not conform to a byte
* boundary. For example, if bitoffs = 3, then translation will
* begin with the 4th bit (offsets are 0-relative) of the passed
* ptr; if lastbyt == YES, then only the remaining 5 bits will
* be translated (offsets 3 thru 7); otherwise, a full 8 bits
* will be translated, the remaining 3 coming from the left 3
* bits of the byte following ptr. Issuing a call with a ZERO
* bit offset like:
*
* mychar = bit2byte(there, 0, anything);
*
* is equivalent to: mychar = *there;
*/
char bit2byte(ptr, bitoffs, lastbyt)
char *ptr; /* Ptr to starting byte to take from */
short bitoffs; /* Offset of starting bit from ptr, 0-7 */
BOOL lastbyt; /* Flag: Do not take bits from next char if set */
{
char byte;
if (ptr == NULL || bitoffs < 0 || bitoffs > 7)
return (0);
byte = *ptr << bitoffs; /* Set left side of byte */
if (bitoffs && !lastbyt) /* Set right side from next byte */
byte |= (*(++ptr) >> (8 - bitoffs));
return (byte);
}
/* INSBITS - Insert specified number of bits to bit field beginning at basep,
* starting insertion bitoffs bits from the base. Inserted bits
* will be all of the same value (0 or 1). Bits above the
* insertion point will be pushed up in memory, up the limit of
* total field size fldsize (arbitrary size limit defined by
* TBUFSIZ).
*
* NOTE: If you need a routine to insert a specific bit pattern
* (not just all 0's or 1's), use this as a template. You only
* need to change the "fill middle bytes" section.
*/
short insbits(basep, bitoffs, nbits, val, fldsize)
char *basep; /* Ptr to base of bit field */
short bitoffs; /* Number of bits offset from left to begin insert */
short nbits; /* Number of bits to insert */
short val; /* Value to insert, 1 or 0 */
short fldsize; /* Total size of bit field in bytes */
{
char buffer[TBUFSIZ]; /* Temporary copy buffer */
char *firstbyt, *lastbyt; /* Bytes where insert begins/ends */
short firstoffs, lastoffs; /* Bit offsets in first, last bytes */
short n; /* Field index counter */
short lastbit; /* Offset of last bit in field */
char *ptr; /* Temporary ptr */
if (basep == NULL || nbits <= 0 || fldsize <= 0 || fldsize > TBUFSIZ)
return (FAILURE);
firstbyt = basep + bitoffs / 8;
lastbit = bitoffs + nbits - 1;
lastbyt = basep + lastbit / 8;
firstoffs = bitoffs % 8;
lastoffs = lastbit % 8;
if (firstbyt >= basep + fldsize)
return (FAILURE);
setmem(buffer, sizeof(buffer), 0); /* Init copy buffer */
/* Copy from firstbyt thru end of field to buffer */
for (ptr = firstbyt, n = 0; ptr < basep + fldsize; ptr++, n++)
buffer[n] = bit2byte(ptr, firstoffs, ptr == basep + fldsize - 1);
/* Set the starting byte, leaving left part as is */
if (val)
*firstbyt |= FULLBYT >> firstoffs;
else
*firstbyt &= FULLBYT << (8 - firstoffs);
/* Fill middle bytes; do not overwrite end of field */
for (ptr = firstbyt + 1; ptr < lastbyt; ptr++)
{
if (ptr >= basep + fldsize)
break;
*ptr = (val) ? FULLBYT : 0;
}
/* Set ending byte, leaving right part as is */
if (lastbyt < basep + fldsize && lastbyt != firstbyt)
{
if (val)
*lastbyt |= FULLBYT << (7 - lastoffs);
else
*lastbyt &= FULLBYT >> (lastoffs + 1);
}
/* Write buffer from last byte to end of field */
for (ptr = lastbyt, n = 0; ptr < basep + fldsize; ptr++, n++)
byte2bit(buffer[n], ptr, lastoffs + 1, ptr == basep + fldsize - 1);
return (SUCCESS);
}
/* DELBITS.C - Delete specified number of bits from bit field beginning at
* basep offset by bitoffs bits. The bit field may be any number
* of bytes in length, and the deleted section may be any number
* of bits in length and need not conform to byte boundaries. The
* bits above the deleted section are moved down to fill the
* gap, and the top of the field filled with the specified value.
*
* NOTE: Bit field size fldsize is arbitrarily limited to TBUFSIZ as
* defined below.
*/
short delbits(basep, bitoffs, nbits, val, fldsize)
char *basep; /* Ptr to base of bit field */
short bitoffs; /* Number of bits offset from left to begin delete */
short nbits; /* Number of bits to delete */
short val; /* Value to fill vacated right side of field, 1 or 0 */
short fldsize; /* Total size of bit field in BYTES */
{
char buffer[TBUFSIZ]; /* Temporary copy buffer */
char *firstbyt, *lastbyt; /* Bytes where delete begins/ends */
short firstoffs, lastoffs; /* Bit offsets in first, last bytes */
short n; /* Field index counter */
short lastbit; /* Offset of last bit in field */
char *ptr; /* Temporary ptr */
if (basep == NULL || nbits <= 0 || fldsize <= 0 || fldsize > TBUFSIZ)
return (FAILURE);
firstbyt = basep + bitoffs / 8;
lastbit = bitoffs + nbits - 1;
lastbyt = basep + lastbit / 8;
firstoffs = bitoffs % 8;
lastoffs = lastbit % 8;
if (firstbyt >= basep + fldsize)
return (FAILURE);
if (val)
setmem(buffer, sizeof(buffer), FULLBYT); /* Init copy buffer */
else
setmem(buffer, sizeof(buffer), 0);
/* Copy to buffer: From bit after end of deleted section to end of field */
if (++lastoffs > 7)
{
lastbyt++;
lastoffs = 0;
}
for (ptr = lastbyt, n = 0; ptr < basep + fldsize; ptr++, n++)
buffer[n] = bit2byte(ptr, lastoffs, ptr == basep + fldsize - 1);
/* Write buffer to deleted part thru end of field; end is filled with val */
for (ptr = firstbyt, n = 0; ptr < basep + fldsize; ptr++, n++)
byte2bit(buffer[n], ptr, firstoffs, ptr == basep + fldsize - 1);
return (SUCCESS);
}
/* BITZVALU - Evaluate the next nbits bits from the starting char * and bit
* offset and return the value. Uses a simple counting algorithm,
* starting with the rightmost bit in the designated field and
* moving left, adding a successive power of 2 for each "on" bit.
*
* EXAMPLES: Given a pointer to the array of hex values: 1E A4 7C
*
* bitzvalu(ptr, 8, 8) returns 164 (00A4)
* bitzvalu(ptr, 3, 4) returns 15 (000F)
* bitzvalu(ptr, 10, 10) returns 583 (0247)
*
* NOTE: Returns an unsigned value. The number of bits evaluated may not
* be more than 16. If bad parameters are passed, returns 0.
*/
unsigned bitzvalu(ptr, bitoffs, nbits)
char *ptr; /* Ptr to starting byte to take from */
short bitoffs; /* Offset of starting bit from ptr */
short nbits; /* Number of bits to evaluate */
{
unsigned num = 0; /* Initialize all bits to 0 */
int bit;
unsigned mult = 1;
if (ptr == NULL || nbits < 1 || nbits > 16)
return (0);
for (bit = nbits - 1; bit >= 0; bit--, mult *= 2)
num += (getbit(ptr, bitoffs + bit) * mult);
return (num);
}
/* CONTRIBUTED BY: Gordon Kramer, Liberty Tree Software, Belchertown, MA */